package water;

import java.util.List;
import java.util.Stack;
import java.util.Vector;

import model.Board;

public class UnWaterBoard extends Board {

    @Override
    public void reset() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

	public class State {
		int c3;

		int c4;
		WMove move;
		
		State(){};
		
		public State(WMove move,State state) {
			this.c3 = state.c3;
			this.c4 = state.c4;
			this.move=move;
		}
	}

	int work=0;
	
	State state;

	Stack<State> history = new Stack<State>();

	List<WMove> allMoves = new Vector<WMove>();

	private boolean undoing;;



	
	public UnWaterBoard() {
		state=new State();
	}

	@Override
	public List<Move> getMoves() {
		List<Move> possibeMoves = new Vector<Move>();
		for (WMove m : allMoves) {
			if (m.canMove())
				possibeMoves.add(m);
		}
		return possibeMoves;
	}

	@Override
	public boolean hasWon() {
		return state.c4 == 2;
	}

	@Override
	public long longHashCode() {
		return state.c4 * 10 + state.c3;
	}

	@Override
	public boolean undo() {
		if (history.isEmpty())
			return false;
		work++;
		undoing=true;
		state=history.pop();
		setChanged();
		notifyObservers();
		return true;
	}

	private void saveState(WMove move) {
		work++;
		State saveMe = new State(move,state);
		undoing=false;
		history.push(saveMe);
	}

	abstract class WMove extends Move {

		WMove() {
			allMoves.add(this);
		}

		abstract boolean canMove();

		abstract String description();
	}

	
	Move x=new WMove() {
		public void doMove() {
			saveState(this);
			state.c4 = 1;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c4 == 0 || state.c4 == 4;
		}

		String description() {
			return "Fill/Empty C4=1";
		}

	};
	
	

	Move f42 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c4 = 2;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c4 == 0|| state.c4 == 4;
		}

		String description() {
			return "Fill/Empty C4=2";
		}

	};


	Move f43 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c4 = 3;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c4 == 0|| state.c4 == 4;
		}

		String description() {
			return "Fill/Empty C4=3";
		}

	};


	Move f44 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c4 = 4;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c4 == 0;
		}

		String description() {
			return "Empty C4=4";
		}

	};

	
	// EMPTY 3

	Move f31 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c3 = 1;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c3 == 0|| state.c3 == 3;
		}

		String description() {
			return "UnEmpty C3=1";
		}

	};

	

	Move f32 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c3 = 2;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c3 == 0 || state.c3 == 3;
		}

		String description() {
			return "UnEmpty C3=2";
		}

	};


	Move f33 = new WMove() {
		public void doMove() {
			saveState(this);
			state.c3 = 3;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c3 == 0 || state.c3 == 3 ;
		}

		String description() {
			return "UnEmpty C3=3";
		}

	};

	
	
	Move p34 = new WMove() { // c3 into c4
		public void doMove() {
			saveState(this);
			int cap = 4 - state.c4;
			int pour = Math.min(cap, state.c3);
			state.c4 += pour;
			state.c3 -= pour;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c3 > 0 && state.c4 < 4;
		}

		String description() {
			return "C3 ---> C4";
		}

	};

	Move p43 = new WMove() { // c4 into c3
		public void doMove() {
			saveState(this);
			int cap = 3 - state.c3;
			int pour = Math.min(cap, state.c4);
			state.c3 += pour;
			state.c4 -= pour;
			setChanged();
			notifyObservers();
		}

		boolean canMove() {
			return state.c4 > 0 && state.c3 < 3;
		}

		String description() {
			return "C4 --> C3";
		}

	};

	public void display() {
	
		if (!undoing) {
			System.out.print(history.peek().move.description());
		} else {
			System.out.print("UNDO        ");
			
		}
		System.out.println("\t"+ state.c4 + ","+ state.c3 );
	//	System.out.println(" depth , work  = "+ history.size() + "  " + work );
	}
	
	public int getDepth() {
		return history.size();
	}
	
	public int getWork() {
		return work;
	}

}
